package com.mldong.tasks;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.mldong.modules.sys.api.TaskExecutionApi;
import com.mldong.modules.sys.dto.TaskExecutionQueueDTO;
import com.mldong.modules.sys.enums.TaskExecutionHistoryStateEnum;
import com.mldong.modules.sys.enums.TaskExecutionQueueStateEnum;
import com.mldong.timer.TaskExecutor;
import com.mldong.timer.TimerTaskRunner;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 * 任务调度器抽象基类
 */
@Slf4j
@RequiredArgsConstructor
public abstract class AbstractTaskExecutionTaskRunner implements TimerTaskRunner {

    protected final TaskExecutionApi taskExecutionApi;

    // 创建自定义线程池用于异步执行任务
    protected final ExecutorService taskExecutor = ThreadUtil.newExecutor();

    @Override
    public void action() {
        try {
            // 获取待执行的任务
            List<TaskExecutionQueueDTO> pendingTasks = getPendingTasks();

            // 逐个执行任务
            for (TaskExecutionQueueDTO task : pendingTasks) {
                executeTask(task);
            }
        } catch (Exception e) {
            log.error("任务调度执行异常", e);
        }
    }

    /**
     * 获取待执行的任务列表，由子类实现具体逻辑
     * @return 任务列表
     */
    protected abstract List<TaskExecutionQueueDTO> getPendingTasks();

    /**
     * 执行单个任务（异步方式）
     * @param task 任务队列记录
     */
    protected void executeTask(TaskExecutionQueueDTO task) {
        try {
            // 立即更新任务状态为执行中，防止重复调度
            if (!taskExecutionApi.updateTaskState(task.getId(), TaskExecutionQueueStateEnum.EXECUTING.getCode(), null)) {
                log.warn("任务状态更新失败，可能已被其他调度器处理，任务ID: {}", task.getId());
                return;
            }

            // 提交到异步线程池执行，避免阻塞调度主线程
            taskExecutor.submit(() -> {
                doExecuteTask(task);
            });
        } catch (Exception e) {
            log.error("提交任务到线程池失败，任务ID: {}", task.getId(), e);
            handleTaskFailure(task, e.getMessage());
        }
    }

    /**
     * 实际执行任务逻辑
     * @param task 任务队列记录
     */
    private void doExecuteTask(TaskExecutionQueueDTO task) {
        try {
            // 获取Spring Bean并执行任务（使用hutool的SpringUtil工具）
            Object bean = SpringUtil.getBean(task.getSpringBeanName());
            if (bean instanceof TaskExecutor) {
                TaskExecutor executor = (TaskExecutor) bean;

                // 解析扩展参数
                Dict ext = Dict.create();
                if (task.getVariable() != null && !task.getVariable().isEmpty() && !task.getVariable().equals("{}")) {
                    ext = JSONUtil.toBean(task.getVariable(), Dict.class);
                }

                // 执行任务
                boolean success = executor.execute(task.getBizId(), ext);

                // 根据执行结果处理任务状态
                handleTaskResult(task, success);
            } else {
                // Bean不支持任务执行接口
                handleTaskFailure(task, "Bean不支持TaskExecutor接口");
            }
        } catch (Exception e) {
            // 任务执行异常
            log.error("执行任务失败，任务ID: {}", task.getId(), e);
            handleTaskFailure(task, e.getMessage());
        }
    }

    /**
     * 处理任务执行结果
     * @param task 任务队列记录
     * @param success 执行是否成功
     */
    private void handleTaskResult(TaskExecutionQueueDTO task, boolean success) {
        if (success) {
            // 任务执行成功，归档到历史表
            taskExecutionApi.archiveTaskToHistory(task.getId(), TaskExecutionHistoryStateEnum.SUCCESS.getCode(), new Date());
        } else {
            // 任务执行失败，处理重试逻辑
            handleTaskFailure(task, "任务执行返回失败");
        }
    }

    /**
     * 处理任务失败
     * @param task 任务队列记录
     * @param errorMsg 错误信息
     */
    private void handleTaskFailure(TaskExecutionQueueDTO task, String errorMsg) {
        // 增加错误计数
        int newErrorCount = taskExecutionApi.incrementErrorCount(task.getId());

        // 判断是否超过最大重试次数
        if (newErrorCount >= task.getAllowMaxErrorCount()) {
            // 超过最大重试次数，归档为失败状态
            taskExecutionApi.archiveTaskToHistory(task.getId(), TaskExecutionHistoryStateEnum.FAILED.getCode(), new Date());
        } else {
            // 未超过最大重试次数，标记为待重试状态
            taskExecutionApi.updateTaskState(task.getId(), TaskExecutionHistoryStateEnum.FAILED.getCode(), errorMsg);
        }
    }
}
